﻿// -----------------------------------------------------------------------
// <copyright file="PngImageTest.cs">
// Copyright (c) 2013 Andrey Veselov. All rights reserved.
// License:  Microsoft Public License (MS-PL)
// Contacts: http://andrey.moveax.com  andrey@moveax.com
// </copyright>
// -----------------------------------------------------------------------

namespace PortableImagingLibrary.Png.Crc
{
    using System;

    internal class Crc32 : ICrc
    {
        private const int _crcTableSize = 256;
        private const uint _crcDefaultValue = 4294967295u;

        private readonly uint[] _crcTable = new uint[Crc32._crcTableSize];
        private bool _isCrcTableBuit = false;
        private uint _crc = Crc32._crcDefaultValue;

        public uint CurrentValue { get { return this._crc ^ Crc32._crcDefaultValue; } }

        public void Reset()
        {
            this._crc = Crc32._crcDefaultValue;
        }

        public void Update(string value)
        {
            if (!this._isCrcTableBuit)
                this.BuildCrcTable();

            for (int index = 0; index < value.Length; index++)
                this._crc = (this._crcTable[(int)((UIntPtr)((this._crc ^ (uint)((byte)value[index])) & 255u))] ^ this._crc >> 8);

        }

        public void Update(byte[] buffer)
        {
            if (!this._isCrcTableBuit)
                this.BuildCrcTable();

            for (int index = 0; index < buffer.Length; index++)
                this._crc = (this._crcTable[(int)((UIntPtr)((this._crc ^ (uint)buffer[index]) & 255u))] ^ this._crc >> 8);
        }

        private void BuildCrcTable()
        {
            for (int i = 0; i < Crc32._crcTableSize; i++) {
                var c = (uint)i;

                for (int j = 0; j < 8; j++)
                    c = (((c & 1u) != 0u) ? (3988292384u ^ c >> 1) : (c >> 1));

                this._crcTable[i] = c;
            }

            this._isCrcTableBuit = true;
        }
    }
}
